/*
                    Frame Class Implementation
*/
#include "Frame.h"

FrameTab::FrameTab()
{
    strName = "";
}

FrameTab::~FrameTab()
{
    Widgets.clear();
}

int FrameTab::AddWidget(Widget *pNewWidget)
{
    Widgets.push_back(pNewWidget);
}

int FrameTab::Hide()
{
    for (int i = 0; i < Widgets.size(); i++)
    {
        Widgets.at(i)->setVisible(false);
    }
}

int FrameTab::Show()
{
    for (int i = 0; i < Widgets.size(); i++)
    {
        Widgets.at(i)->setVisible(true);
    }
}

void FrameTab::setName(const string& strNewName)
{
    strName = strNewName;
}

string FrameTab::getName()
{
    return strName;
}

Frame::Frame()
{
    bVisible = true;
    bFixed = false;
    bDragging = false;
    bHasFocus = false;

    Background = NULL;

    iWidth = 0;
    iHeight = 0;

    strName = "";

    Position = Point(0, 0);
}

Frame::~Frame()
{
    for (int i = 0; i < Widgets.size(); i++)
    {
        delete Widgets.at(i);
    }

    Widgets.clear();

    while (!EventBuffer.empty())
    {
          delete EventBuffer.front();
          EventBuffer.pop();
    }

    for (map<string, FrameTab*>::iterator iter = Tabs.begin(); iter != Tabs.end(); iter++)
    {
        delete iter->second;
    }

    Tabs.clear();

    SDL_FreeSurface(Background);
}

int Frame::Initialise(Point NewPosition, int iNewWidth, int iNewHeight)
{
    Position = NewPosition;

    iWidth = iNewWidth;
    iHeight = iNewHeight;
}

int Frame::HandleMouseDown(int iMouseX, int iMouseY)
{
    double xpos = Position.x;
    double ypos = Position.y;

    bool bWidgetEvent = false;

    if((iMouseX > xpos) && (iMouseX < xpos + iWidth) && (iMouseY > ypos) && (iMouseY < ypos + iHeight))
    {
        if (bVisible == true)
        {
            for (int i = 0; i < Widgets.size(); i++)
            {
                if (Widgets.at(i)->getEnabled() == true && Widgets.at(i)->getVisible() == true)
                {
                    if (Widgets.at(i)->HandleMouseDown(iMouseX - (int)Position.x, iMouseY - (int)Position.y) == 1)
                    {
                       EventBuffer.push(new GUIEvent(GUIEVENT_LEFTMOUSEDOWN, Widgets.at(i)->getName()));

                       bWidgetEvent = true;
                    }
                }
            }

            if (bFixed == false)
            {
                if (bWidgetEvent == false)
                {
                    bDragging = true;
                }
            }
        }
    }

    return 0;
}

bool Frame::CheckFocus(int iMouseX, int iMouseY)
{
    if (bVisible == false)
    {
        return false;
    }

    double xpos = Position.x;
    double ypos = Position.y;

    if((iMouseX > xpos) && (iMouseX < xpos + iWidth) && (iMouseY > ypos) && (iMouseY < ypos + iHeight))
    {
        return true;
    }
    else
    {
        return false;
    }
}

int Frame::HandleMouseUp(int iMouseX, int iMouseY)
{
    if (bVisible == true)
    {
        for (int i = 0; i < Widgets.size(); i++)
        {
            if (Widgets.at(i)->getEnabled() == true && Widgets.at(i)->getVisible() == true)
            {
                if (Widgets.at(i)->HandleMouseUp(iMouseX - (int)Position.y, iMouseY - (int)Position.y) == 1)
                {
                   EventBuffer.push(new GUIEvent(GUIEVENT_LEFTMOUSEUP, Widgets.at(i)->getName()));
                }
            }
        }
    }

    bDragging = false;

    return 0;
}

int Frame::HandleMouseMotion(int iMouseXREL, int iMouseYREL)
{
    bool bTooltipShown = false;

    if (bDragging == true)
    {
        Position.x += iMouseXREL;
        Position.y += iMouseYREL;

        for (int i = 0; i < Widgets.size(); i++)
        {
            Widgets.at(i)->setFramePosition(Position);
        }
    }
    else if (bVisible == true)
    {
       for (int i = 0; i < Widgets.size(); i++)
       {
           if (Widgets.at(i)->getEnabled() == true && Widgets.at(i)->getVisible() == true)
           {
                if (Widgets.at(i)->HandleMouseMotion(iMouseXREL, iMouseYREL) == 2)
                {
                    //CursorEngine::ShowTooltip(Widgets.at(i)->getTooltip());
                    bTooltipShown = true;
                }
           }
       }
    }
    else
    {
        return -1;
    }

    if (bTooltipShown == true)
    {
        return 2;
    }
    else
    {
        return 0;
    }
}

int Frame::HandleWindowResize(int iWindowWidth, int iWindowHeight)
{

    return 0;
}

int Frame::HandleKeyDown(string strKeyName, Uint16 UNICODEvalue)
{
    if (bVisible == true)
    {
        for (int i = 0; i < Widgets.size(); i++)
        {
            if (Widgets.at(i)->getEnabled() == true && Widgets.at(i)->getVisible() == true)
            {
                if (Widgets.at(i)->HandleKeyDown(strKeyName, UNICODEvalue) == 1)
                {
                    EventBuffer.push(new GUIEvent(GUIEVENT_KEYDOWN, Widgets.at(i)->getName()));
                }
            }
        }
    }

    return 0;
}

void Frame::setVisible(bool bNewVisible)
{
     bVisible = bNewVisible;
}

bool Frame::getVisible()
{
     return bVisible;
}

int Frame::AddWidget(Widget *pNewWidget, string strWidgetName)
{
    Widgets.push_back(pNewWidget);
    Widgets.back()->setName(strWidgetName);
    Widgets.back()->setFramePosition(Position);
}

int Frame::BlitToSurface(SDL_Surface *surface)
{
    if (bVisible == true)
    {
        if (Background != NULL)
        {
            SDL_Rect dest;
            dest.x = static_cast<int>(Position.x);
            dest.y = static_cast<int>(Position.y);
            SDL_BlitSurface(Background, NULL, surface, &dest);
        }

        SDL_Rect clip;

        clip.x = static_cast<int>(Position.x);
        clip.y = static_cast<int>(Position.y);
        clip.w = iWidth;
        clip.h = iHeight;

        // Stop widgets overflowing the frame area
        SDL_SetClipRect(surface, &clip);

        for (int i = 0; i < Widgets.size(); i++)
        {
            Widgets.at(i)->setFramePosition(Position);

            if (Widgets.at(i)->getVisible() == true)
            {
                Widgets.at(i)->BlitToFrame(surface, Position);
            }
        }

        // Reset the screen clip rect to the full surface
        SDL_SetClipRect(surface, NULL);
    }
}

int Frame::GetWidgetByName(string strName)
{
    for (int i = 0; i < Widgets.size(); i++)
    {
        if (Widgets.at(i)->getName() == strName)
        {
           return i;
        }
    }

    return -1;
}

int Frame::PollEvent(GUIEvent &event)
{
     if (EventBuffer.empty() != true)
     {
        event = *EventBuffer.front();
        delete EventBuffer.front();
        EventBuffer.pop();

        return 0;
     }
     else
     {
         return -1;
     }
}

int Frame::setBackground(SDL_Surface *NewBackground)
{
    SDL_FreeSurface(Background);

    Background = NewBackground;

    if (Background != NULL)
    {
        iWidth = Background->w;
        iHeight = Background->h;
    }

    return 0;
}

int Frame::setBackground(string strFilepath)
{
    SDL_FreeSurface(Background);

    Background = IMG_Load(strFilepath.c_str());

    if (Background != NULL)
    {
        iWidth = Background->w;
        iHeight = Background->h;

        Background = OptimiseAlphaSurface(Background);
    }

    return 0;
}

Point Frame::getPosition()
{
    return Position;
}

void Frame::setName(string strNewName)
{
    strName = strNewName;
}

string Frame::getName()
{
    return strName;
}

void Frame::MoveRelative(int iXREL, int iYREL)
{
    Position.x += iXREL;
    Position.y += iYREL;
}

void Frame::setFixed(bool bNewFixed)
{
    bFixed = bNewFixed;
}

int Frame::CreateTab(const string& strTab)
{
    if (KeyInMap(Tabs, strTab) == false)
    {
        Tabs[strTab] = new FrameTab;
        Tabs[strTab]->setName(strName);

        return 0;
    }
    else
    {
        return -1;
    }
}

int Frame::AddWidgetToTab(const string& strTab, Widget *pNewWidget)
{
    if (KeyInMap(Tabs, strTab) == true)
    {
        Tabs[strTab]->AddWidget(pNewWidget);

        return 0;
    }
    else
    {
        return -1;
    }
}

int Frame::SetVisibleTab(const string& strTab)
{
    if (KeyInMap(Tabs, strTab) == true)
    {
        for (map<string, FrameTab*>::iterator iter = Tabs.begin(); iter != Tabs.end(); iter++)
        {
            if (iter->first == strTab)
            {
                iter->second->Show();
            }
            else
            {
                iter->second->Hide();
            }
        }

        return 0;
    }
    else
    {
        return -1;
    }
}

void Frame::ToggleVisible()
{
    if (bVisible == false)
    {
        bVisible = true;
    }
    else
    {
        bVisible = false;
    }
}

void Frame::WindowAlign(const int& iAlignType, const Point WindowSize)
{
    if (iAlignType == ALIGN_CENTER)
    {
        Position.x = (WindowSize.x / 2) - (iWidth / 2);
        Position.y = (WindowSize.y / 2) - (iHeight / 2);
    }
    else if (iAlignType == ALIGN_BOTTOM)
    {
        Position.y = WindowSize.y - iHeight;
    }
    else if (iAlignType == ALIGN_TOP)
    {
        Position.y = 0;
    }
    else if (iAlignType == ALIGN_LEFT)
    {
        Position.x = 0;
    }
    else if (iAlignType == ALIGN_RIGHT)
    {
        Position.x = WindowSize.x - iWidth;
    }
}

void Frame::setPosition(Point NewPos)
{
    Position = NewPos;
}
